package com.alfred.mall.miaosha.biz.service;

import com.alfred.common.framwork.constant.MiaoshaConstant;
import com.alfred.common.framwork.exception.ServiceException;
import com.alfred.common.framwork.util.SnowFlake;
import com.alfred.mall.miaosha.api.MiaoshaGoodsServcie;
import com.alfred.mall.miaosha.api.bo.MiaoshaGoodsBO;
import com.alfred.mall.miaosha.api.dto.MiaoshaOrderRequestDTO;
import com.alfred.mall.miaosha.api.dto.MiaoshaRequestDTO;
import com.alfred.mall.miaosha.api.dto.MiaoshaResultRequestDTO;
import com.alfred.mall.miaosha.biz.cache.SeckillFinishCache;
import com.alfred.mall.miaosha.biz.cache.SeckillHandingListCache;
import com.alfred.mall.miaosha.biz.cache.SeckillSuccessTokenCache;
import com.alfred.mall.miaosha.biz.convert.MiaoshaGoodsConvert;
import com.alfred.mall.miaosha.biz.dao.MiaoshaGoodsMapper;
import com.alfred.mall.miaosha.biz.dao.MiaoshaOrderMapper;
import com.alfred.mall.miaosha.biz.dataobject.MiaoshaGoodsDO;
import com.alfred.mall.miaosha.biz.dataobject.MiaoshaOrderDO;
import com.alfred.mall.mq.api.SeckillMqSendService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

@Component
@Service(validation = "true")
public class MiaoshaGoodsServiceImpl implements MiaoshaGoodsServcie {

    private static final SnowFlake SNOW_FLAKE=new SnowFlake(2,3);

    @Autowired
    private MiaoshaGoodsMapper miaoshaGoodsMapper;

    @Autowired
    private SeckillFinishCache seckillFinishCache;

    @Autowired
    private SeckillHandingListCache seckillHandingListCache;

    @Autowired
    private SeckillSuccessTokenCache seckillSuccessTokenCache;

    @Autowired
    private MiaoshaOrderMapper miaoshaOrderMapper;

    @Reference
    SeckillMqSendService seckillMqSendService;

    @Override
    public void seckill(MiaoshaRequestDTO miaoshaRequestDTO) {
        //2、先看抢购是否已经结束了，秒杀结束会在redis打标
        if (seckillFinishCache.isFinish(miaoshaRequestDTO.getGoodsRandomName())) {
            //秒杀结束
            throw new ServiceException(MiaoshaConstant.MIAO_SHA_OVER.getCode(), MiaoshaConstant.MIAO_SHA_OVER.getMessage());
        }
        //3、判断是否处理中，如果抢购过，在redis会有记录
        if (seckillHandingListCache.isInHanleList(miaoshaRequestDTO)) {
            //您已经提交过抢购，如果抢购成功请下单，否则耐心等待哦...
            throw new ServiceException(MiaoshaConstant.WAIT_PLACE_ORDER.getCode(), MiaoshaConstant.WAIT_PLACE_ORDER.getMessage());
        }
        //4、标记已请求秒杀
        seckillHandingListCache.addHandleList(miaoshaRequestDTO);

        //5、消息入队列
        seckillMqSendService.sendSeckillMessage(MiaoshaGoodsConvert.INSTANCE.convert(miaoshaRequestDTO));

    }

    /**
     * 查询所有秒杀商品
     *
     * @return
     */
    @Override
    public List<MiaoshaGoodsBO> selectAllMiaoshaGoods() {
        List<MiaoshaGoodsDO> goodsDOList = miaoshaGoodsMapper.selectAllMiaoshaGoods();
        return MiaoshaGoodsConvert.INSTANCE.convert(goodsDOList);
    }

    @Override
    public MiaoshaGoodsBO selectMiaoshaGoodsById(Integer goodsId) {
        return MiaoshaGoodsConvert.INSTANCE.convert(miaoshaGoodsMapper.selectById(goodsId));
    }

    /**
     * 获取抢单token
     *
     * @param resultRequestDTO
     * @return
     */
    @Override
    public String queryToken(MiaoshaResultRequestDTO resultRequestDTO) {
        return seckillSuccessTokenCache.queryToken(resultRequestDTO);
    }


    @Override
    public Long order(MiaoshaOrderRequestDTO orderRequestDTO) {
        //TODO：此处待优化，加缓存
        MiaoshaGoodsDO goods = miaoshaGoodsMapper.selectById(orderRequestDTO.getGoodsId());
        //检查token有效期
        if (!seckillSuccessTokenCache.validateToken(orderRequestDTO.getMobile(), goods.getRandomName(), orderRequestDTO.getToken())) {
            throw new ServiceException(MiaoshaConstant.MIAOSHA_TOKEN_EXPIRE.getCode(), MiaoshaConstant.MIAOSHA_TOKEN_EXPIRE.getMessage());
        }
        //去DB检查是否有可用库存，没有直接结束
        checkStore(goods.getRandomName());

        return reduceStoreAndCreateOrder(orderRequestDTO.getMobile(), orderRequestDTO.getGoodsId());
    }

    private void checkStore(String goodsRandomName) {
        QueryWrapper<MiaoshaGoodsDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("random_name", goodsRandomName);
        MiaoshaGoodsDO goods = miaoshaGoodsMapper.selectOne(queryWrapper);
        if (null == goods || goods.getStore().intValue() <= 0) {
            //redis打标秒杀结束
            seckillFinishCache.setFinish(goodsRandomName);
            //没有库存，抢购结束
            throw new ServiceException(MiaoshaConstant.MIAO_SHA_OVER.getCode(), MiaoshaConstant.MIAO_SHA_OVER.getMessage());
        }
    }


    /**
     * 真正做减库存操作(这里没有采用存储过程的原因：这里并没有高并发，高并发已经在获取token时分流，所以此处没必要用存储过程)
     *
     * @param mobile
     * @param goodsId
     * @return
     */
    private Long reduceStoreAndCreateOrder(String mobile, Integer goodsId) {
        MiaoshaOrderDO orderDO = new MiaoshaOrderDO()
                .setId(SNOW_FLAKE.nextId())
                .setMobile(mobile)
                .setGoodsId(goodsId)
                .setNum(1)
                .setCreateTime(new Date());
        //创建秒杀订单
        miaoshaOrderMapper.insert(orderDO);
        //扣减DB库存
        miaoshaGoodsMapper.updateGoodsStoreById(goodsId);
        return orderDO.getId();
    }
}
